package com.itheima.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.itheima.common.constant.RedisConstant;
import com.itheima.common.entity.PageResult;
import com.itheima.common.entity.QueryPageBean;
import com.itheima.mapper.CheckGroupMapper;
import com.itheima.mapper.SetMealMapper;
import com.itheima.pojo.CheckGroup;
import com.itheima.pojo.Setmeal;
import com.itheima.service.SetMealService;
import freemarker.core.ParseException;
import freemarker.template.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfig;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @className SetMealServiceImpl
 */
@Service
@Transactional
@RequiredArgsConstructor
@Slf4j
public class SetMealServiceImpl implements SetMealService {

    private final SetMealMapper setMealMapper;
    private final CheckGroupMapper checkGroupMapper;
    private final RedisTemplate<String, String> redisTemplate;
    private final FreeMarkerConfigurer freeMarkerConfigurer;
    @Value("${freemarker.out.path}")
    private String outPutPath;

    /**
     * 添加套餐
     * @param checkGroupIds 检查组id集合
     * @param setMeal 套餐
     * @return void
     **/
    public void addSetMeal(List<Integer> checkGroupIds, Setmeal setMeal) {
        setMealMapper.insertSetMeal(setMeal); //先添加套餐
        if (!CollectionUtils.isEmpty(checkGroupIds)) {
            setMealMapper.insertSetMealAndCheckGroupRelation(setMeal.getId(), checkGroupIds); //再添加检查项和检查组关联
        }
        //优化：oss垃圾图片清理，将库中已添加的图片名也存入redis中
        if (StringUtils.isNotBlank(setMeal.getImg())) {
            String fileName = setMeal.getImg().substring(setMeal.getImg().lastIndexOf("/") + 1);
            redisTemplate.opsForSet().add(RedisConstant.DB_IMAGES_KEY, fileName);
        }
        //优化：FreeMarker页面静态化，当添加套餐后需要重新生成静态页面（套餐列表页面、套餐详情页面）
        generateMobileStaticHtml();
    }

    /**
     * 删除套餐
     * @param setMealId 套餐id
     * @return void
     **/
    public void deleteSetMealById(Integer setMealId) {
        setMealMapper.deleteSetMealAndCheckGroupRelation(setMealId); //先删除关联关系
        setMealMapper.deleteSetMealById(setMealId); //再删除套餐
    }

    /**
     * 编辑套餐
     * @param checkGroupIds 检查组id集合
     * @param setMeal 套餐
     * @return void
     **/
    @Override
    public void editSetMeal(List<Integer> checkGroupIds, Setmeal setMeal) {
        setMealMapper.updateSetMeal(setMeal); //先更新套餐
        if (!CollectionUtils.isEmpty(checkGroupIds)) {
            setMealMapper.deleteSetMealAndCheckGroupRelation(setMeal.getId()); // 再删除关联关系
            setMealMapper.insertSetMealAndCheckGroupRelation(setMeal.getId(), checkGroupIds); // 再添加检查项和检查组关联
        }
    }

    /**
     * 根据套餐id查询套餐
     * @param setMealId 套餐id
     * @return Setmeal
     **/
    public Setmeal getSetMealById(Integer setMealId) {
        //写法1：
        /*Setmeal setmeal = setMealMapper.getSetMealById(setMealId); //先查询套餐
        if (setmeal != null) {
            List<Integer> checkGroupIds = checkGroupMapper.selectCheckGroupIdsBySetmealId(setMealId); //再查询检查组id集合
            if (!CollectionUtils.isEmpty(checkGroupIds)) {
                List<CheckGroup> checkGroupList = checkGroupMapper.selectCheckGroupsByIds(checkGroupIds); //再查询检查组集合
                setmeal.setCheckGroups(checkGroupList);
            }
        }
        return setmeal;*/

        //写法2：
        /*return Optional.ofNullable(setMealMapper.getSetMealById(setMealId)) //先查询套餐
                .map(setmeal -> {
                    List<Integer> checkGroupIds = checkGroupMapper.selectCheckGroupIdsBySetmealId(setmeal.getId()); //再查询检查组id集合
                    if (!CollectionUtils.isEmpty(checkGroupIds)) {
                        List<CheckGroup> checkGroupList = checkGroupMapper.selectCheckGroupsByIds(checkGroupIds); //再查询检查组集合
                        setmeal.setCheckGroups(checkGroupList);
                    }
                    return setmeal;
                }).orElse(null);*/

        //写法3：
        return Optional.ofNullable(setMealMapper.getSetMealById(setMealId)) //先查询套餐
                .map(setmeal -> {
                    List<Integer> checkGroupIds = checkGroupMapper.selectCheckGroupIdsBySetmealId(setmeal.getId());
                    Optional.ofNullable(checkGroupIds)
                            .filter(ids -> !ids.isEmpty())
                            .map(checkGroupMapper::selectCheckGroupsByIds)
                            .ifPresent(setmeal::setCheckGroups);
                    return setmeal;
                }).orElse(null);
    }

    /**
     * 分页查询套餐
     * @param queryPageBean 分页条件
     * @return PageResult
     **/
    public PageResult getSetMealByPage(QueryPageBean queryPageBean) {
        PageHelper.startPage(queryPageBean.getCurrentPage(), queryPageBean.getPageSize()); //开始分页
        List<Setmeal> setMealList = setMealMapper.selectSetMealByPage(queryPageBean.getQueryString());
        return new PageResult(new PageInfo(setMealList));
    }

    /**
     * 生成当前方法所需的静态页面
     * @return void
     **/
    private void generateMobileStaticHtml(){
        //1、页面静态化之前查询ftl文件中对应的数据
        List<Setmeal> list = setMealMapper.selectAllSetMeals();

        //2、生成套餐列表静态页面
        Map<String, Object> listMap = new HashMap<>();
        //为模板提供数据，用于生成静态页面
        listMap.put("setmealList",list);
        generateHtml("mobile_setmeal.ftl","m_setmeal.html",listMap);

        //3、生成套餐详情静态页面
        for (Setmeal setmeal : list) {
            Map<String, Object> detailMap = new HashMap<>();
            //为模板提供数据，用于生成静态页面
            detailMap.put("setmeal", setMealMapper.selectSetmealWithCheckGroupsAndItems(setmeal.getId()));
            generateHtml("mobile_setmeal_detail.ftl", "setmeal_detail_" + setmeal.getId() + ".html", detailMap);
        }
    }

    /**
     * 通用的方法，用于生成静态页面
     * @param templateName 模板名称
     * @param htmlPageName 生成的html页面名称
     * @param dataMap 为模板提供数据
     */
    public void generateHtml(String templateName, String htmlPageName, Map<String, Object> dataMap) {
        // 使用 try-with-resources 自动管理资源
        try (Writer out = new FileWriter(new File(outPutPath, htmlPageName))) {
            // 获取配置和模板
            Configuration configuration = freeMarkerConfigurer.getConfiguration();
            Template template = configuration.getTemplate(templateName);
            // 处理模板
            template.process(dataMap, out);
            log.info("成功生成静态页面: {}", htmlPageName);
        } catch (IOException e) {
            log.error("IO操作异常，生成页面失败: {}", htmlPageName, e);
            throw new RuntimeException("生成静态页面失败", e);
        } catch (TemplateException e) {
            log.error("模板处理异常", e);
            throw new RuntimeException("模板处理错误", e);
        }
    }
}
